package com.ziytek.web.citizen.configuration.aop;

import com.ziytek.web.citizen.configuration.db.DDS;
import com.ziytek.web.citizen.configuration.db.DynamicDatasourceHolder;
import com.ziytek.web.citizen.constant.DdsConstant;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.util.Objects;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @author fenghx
 * @version 1.0
 * @className DataSourceAspect
 * Description:
 * @date 2024/3/11 19:54
 */
@Slf4j
@Aspect
@Component
public class DataSourceAspect {

    private static final ReadWriteLock READ_WRITE_LOCK = new ReentrantReadWriteLock();

    /**
     * 切点，切的是带有@DDS的注解
     */
    @Pointcut("@annotation(com.ziytek.web.citizen.configuration.db.DDS)")
    public void dynamicDatasourcePointcut() {

    }

    /**
     * 环绕通知
     *
     * @param joinPoint joinPoint
     * @throws Throwable e
     */
    @Around("dynamicDatasourcePointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        //类上的注解
        Class<?> targetClass = joinPoint.getTarget().getClass();
        DDS annotation = targetClass.getAnnotation(DDS.class);
        //方法上的注解
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        DDS annotationMethod = methodSignature.getMethod().getAnnotation(DDS.class);
        String datasourceKey = Objects.nonNull(annotationMethod) ? annotationMethod.value() : annotation.value();
        // 写数据
        if (datasourceKey.contains(DdsConstant.DS_MASTER) || datasourceKey.contains(DdsConstant.DS_BASIC)) {
            try {
                READ_WRITE_LOCK.writeLock().lock();
                DynamicDatasourceHolder.setDataSource(datasourceKey);
                return joinPoint.proceed();
            } catch (Exception e) {
                log.error("写锁保护代码发生异常", e);
                throw e;
            } finally {
                READ_WRITE_LOCK.writeLock().unlock();
                DynamicDatasourceHolder.removeDataSource();
            }
        } else {
            // 读取数据
            try {
                READ_WRITE_LOCK.readLock().lock();
                DynamicDatasourceHolder.setDataSource(datasourceKey);
                //log.info("切换查询从库数据源:{}", datasourceKey);
                return joinPoint.proceed();
            } catch (Exception e) {
                log.error("读锁保护代码发生异常", e);
                throw e;
            } finally {
                READ_WRITE_LOCK.readLock().unlock();
                DynamicDatasourceHolder.removeDataSource();
            }
        }
    }
}